import {ProColumns} from "@ant-design/pro-table";
import {TableConfig} from "@/pages/report/TableConfigList/data";
import moment from "moment";
import E from "wangeditor";
import {modulesUrl} from "@/assets/constant/modulesUrl";
import {ServiceParams} from "@/assets/utils/data";
import {FormInstance, message, Modal} from "antd";
import {save} from "@/assets/service/baseService";
import {history} from "@@/core/history";

/**
 * UUID生成器
 * @param len 长度 number
 * @param radix 随机数基数 number
 * @returns {string}
 */
export const uuid = (len: number, radix: number = 62) => {
  const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(
    ''
  )
  const uuid = []
  let i

  if (len) {
    // Compact form
    for (i = 0; i < len; i++) {
      uuid[i] = chars[Math.floor(Math.random() * radix)]
    }
  } else {
    // rfc4122, version 4 form
    let r

    // rfc4122 requires these characters
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
    uuid[14] = '4'

    // Fill in random data.  At i==19 set the high bits of clock sequence as
    // per rfc4122, sec. 4.1.5
    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = Math.floor(Math.random() * 16)
        uuid[i] = chars[i === 19 ? ((r % 4) % 8) + 8 : r]
      }
    }
  }
  return uuid.join('')
}

/**
 * 用户hooks useState的set，防止一些hooks的坑
 * @param setDataFunction   set方法
 * @param newData   新数据
 * @param callback 成功回调
 * @param isConcat  为数组时，是否为合并，默认为false，覆盖原数组
 */
export function hooksSet(setDataFunction: any, newData: any, callback?: any, isConcat?: boolean) {
  setDataFunction((data: any) => {
    if (newData !== undefined && newData !== null) {
      if (newData.constructor === Object) {
        data = Object.assign({}, data, newData)
      }
      if (newData.constructor.name === "String" || newData.constructor.name === "HTMLTableRowElement") {
        data = newData
      }
      if (newData.constructor === Array) {
        if (newData === undefined) {
          newData = [];
        }
        if (isConcat) {
          data = data.slice().concat(newData)
        } else {
          data = newData.slice()
        }
      }
    }
    callback && callback(data)
    return data;
  })
}

/**
 * 制作ProTable的选择列表数据
 * @param selectList
 */
export function makeProTableSelectList(selectList: { label: string, value: string }[]) {
  let result = {};
  selectList && selectList.forEach(function (n: { label: string, value: string }, i) {
    result[i] = {text: n}
  })
  return result
}

/**
 * 根据字典值获取字典标签
 * @param selectList
 */
export function getLabel(dictList: any, value: any) {
  let result;
  dictList?.forEach((dict: any) => {
    if (dict.value === value) {
      result = dict.label;
      return;
    }
  })
  return result;
}

/**
 * 修改Columns中的数据
 * @param columns
 * @param setColumns
 * @param dataIndex  需要修改的字段dataIndex
 * @param json   需要修改的json
 */
export function modifyColumns(columns: any, dataIndex: string, json: {}) {
  let newColumns: ProColumns<TableConfig>[] = []
  columns.forEach((column: ProColumns<TableConfig>) => {
    if (column.dataIndex === dataIndex) {
      newColumns.push(Object.assign({}, column, json))
    } else {
      newColumns.push(column)
    }
  })
  return newColumns;
}

/**
 * 获取api接口前缀
 * @param module 模块名
 */
export function getApiPrefix(module: string) {
  let serviceParams: ServiceParams = getServiceParams();
  return serviceParams.mapping + serviceParams.apiPrefix + serviceParams.version + module
}

/**
 * 请求时，参数支持嵌套参数，把true和false改为1和0
 */
export function paramsChange(params: any) {
  let newParams = {};
  for (let key in params) {
    let value = params[key];
    if (key != "newRecord" && value != undefined && value.toString() === "true") {
      params[key] = "1";
    }
    if (key != "newRecord" && value != undefined && value.toString() === "false") {
      params[key] = "0";
    }
    if (key.indexOf(".") != -1) {
      // 以“.”分割
      let keys = key.split(".");
      newParams[keys[0]] = Object.assign({}, newParams[keys[0]], {[keys[1]]: params[key]})
    } else {
      newParams[key] = params[key]
    }
  }
  return newParams;
}

/**
 * 日期格式化
 * @param date
 */
export function dateFormat(date: string | undefined, format?: string) {
  let result;
  if (date) {
    result = moment(date).format(format || 'YYYY-MM-DD HH:mm:ss');
  }
  return result;
}

/**
 * 创建富文本框
 * @param elementId
 */
export function createEditor(elementId: string, onChange: any) {
  let serviceParams = getServiceParams();
  // 显示富文本编辑器
  let editor: E = new E("#" + elementId)
  // 配置菜单栏，设置不需要的菜单
  editor.config.excludeMenus = [
    // // 图片
    // 'image',
    'emoticon',
    // 表格
    'table',
    // 视频
    'video'
  ]
  // 配置图片上传地址
  // editor.config.uploadImgServer = serviceParams.wangEditorUploadUrl
  editor.config.uploadImgServer = serviceParams.uploadUrl
  // 配置图片上传的参数名
  editor.config.uploadFileName = 'file'
  // 关闭粘贴样式删除
  editor.config.pasteFilterStyle = false
  // 忽略粘贴的图片
  editor.config.pasteIgnoreImg = true
  // 配置粘贴文本的内容处理
  editor.config.pasteTextHandle = function (pasteString: string) {
    // 对粘贴的文本进行处理，然后返回处理后的结果
    // 这里先去掉可能会出现的一些乱七八糟的字符
    let pasteStrings: string[] = pasteString.split("div.Section0{page:Section0;}");
    return pasteStrings.length > 1 ? pasteStrings[1] : pasteStrings[0];
  }
  // 配置 onchange 回调函数
  editor.config.onchange = function (newHtml: string) {
    onChange && onChange(newHtml)
  }
  editor.config.uploadImgHooks = {
    // // 上传图片之前
    // before: function(xhr) {
    //   console.log(xhr)
    //
    //   // 可阻止图片上传
    //   return {
    //     prevent: true,
    //     msg: '需要提示给用户的错误信息'
    //   }
    // },
    // // 图片上传并返回了结果，图片插入已成功
    // success: function(xhr) {
    //   console.log('success', xhr)
    // },
    // // 图片上传并返回了结果，但图片插入时出错了
    // fail: function(xhr, editor, resData) {
    //   console.log('fail', resData)
    // },
    // // 上传图片出错，一般为 http 请求的错误
    // error: function(xhr, editor, resData) {
    //   console.log('error', xhr, resData)
    // },
    // // 上传图片超时
    // timeout: function(xhr) {
    //   console.log('timeout')
    // },
    // 图片上传并返回了结果，想要自己把图片插入到编辑器中
    // 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式，可使用 customInsert
    customInsert: function (insertImgFn, result) {
      result.data.forEach((annex) => {
        // @ts-ignore
        insertImgFn(serviceParams.downloadFileUrl + "?id=" + annex.id)
      })
    }
  }
  editor.create()
  return editor;
}

/**
 * 判断字符串是否为空或空串
 * @param elementId
 */
export function isBlank(str?: string) {
  return !isNotBlank(str)
}

/**
 * 判断字符串是否为空或空串
 * @param elementId
 */
export function isNotBlank(str?: string) {
  if (str === undefined || str === null || str?.length === 0) {
    return false;
  } else {
    return true;
  }
}

/**
 * 判断数组是否为空或长度为空
 * @param elementId
 */
export function isNotEmpty(arrays?: any[]) {
  if (arrays === undefined || arrays === null || arrays?.length === 0) {
    return false;
  } else {
    return true;
  }
}

/**
 * 下载文件，可修改文件名
 * @param annexId 附件id
 * @param name 下载显示的文件名
 */
export const downloadFile = (annexId?: string, name?: string) => {
  imitateAClick(getServiceParams().downloadFileUrl + "?id=" + annexId, name)
}

/**
 * 模仿超链接点击下载
 * @param href
 * @param name 下载显示的文件名
 */
export const imitateAClick = (href: string, name?: string) => {
  console.log(href)
  if (href && name) {
    const link = document.createElement('a')
    link.style.display = 'none'
    link.href = href
    link.setAttribute('download', name || "")
    document.body.appendChild(link)
    link.click()
    link.remove()
  }
}

/**
 * 获取服务器后台参数
 */
export const getServiceParams = () => {

  let mapping: string = REACT_APP_ENV === "test" ? "/testDsp" : "/dsp";
  let apiPrefix: string = "/api";
  let version: string = "/v1";
  let uploadUrl: string = mapping + apiPrefix + version + modulesUrl.sysAnnex + "/upload";
  let wangEditorUploadUrl: string = mapping + apiPrefix + version + modulesUrl.sysAnnex + "/wangEditorUpload";
  let downloadFileUrl: string = mapping + apiPrefix + version + modulesUrl.sysAnnex + "/download";

  let serviceParams: ServiceParams = {
    mapping: mapping,
    apiPrefix: apiPrefix,
    version: version,
    uploadUrl: uploadUrl,
    wangEditorUploadUrl: wangEditorUploadUrl,
    downloadFileUrl: downloadFileUrl,
  }
  return serviceParams;
}

/**
 * 从以","分割的字符串组中，删除指定字符串
 * @param string
 * @param oldString
 */
export const deleteOfStrings = (string: string, oldString: string) => {
  let result;
  let newStrings: string[] = [];
  // 以“,”分割，遍历筛掉需要删除的字符串，重新组装数组
  if (isNotBlank(oldString) && isNotBlank(string)) {
    let oldStrings: string[] = oldString.split(",")
    oldStrings.forEach((s) => {
      if (s !== string) {
        newStrings.push(s);
      }
    })
  }
  if (newStrings.length > 0) {
    result = newStrings.join(",")
  }
  return result;
}

/**
 * 修改json数组中的，满足key-value与原json相等的json进行修改（此处修改只修改传入newJson中有的，没有的保持原状）
 * @param jsonArray
 * @param key （支持多层，以“.”隔开）
 * @param value （支持传入数组或字符串，注意：传入"modifyAll"，则表示修改所有满足key的json）
 * @param newJson
 */
export const modifyJsonArray = (jsonArray: {}[], keys: string, value: any, newJson: {}) => {
  let resultJsonArray: any[] = [];
  if (jsonArray.length > 0) {
    // 遍历数组
    jsonArray.forEach((json) => {
      // 判断key是否为多层
      let keyArray: string[] = keys.split(".");
      // 获取value
      let oldValue: any = undefined;
      keyArray.forEach((key) => {
        oldValue = oldValue ? oldValue[key] : json[key]
      })
      // 判断是否满足，满足则替换
      if (oldValue === value) {
        resultJsonArray.push(Object.assign({}, json, newJson))
      } else {
        resultJsonArray.push(Object.assign({}, json))
      }
    })
  }
  return resultJsonArray;
}

/**
 * json数组中，删除指定数据
 * @param key 需要删除数的key
 * @param value 需要删除数的value
 * @param jsonArrays
 */
export const deleteOfJsonArrays = (key: string, value: any, jsonArrays: any[]) => {
  let result: any[] = [];
  // 以“,”分割，遍历筛掉需要删除的字符串，重新组装数组
  if (isNotBlank(key) && isNotEmpty(jsonArrays)) {
    jsonArrays.forEach((json) => {
      if (value !== json[key]) {
        result.push(json)
      }
    })
  }
  return result;
}

/**
 * 删除提示框
 * @param okCallback
 */
export const deleteConfirm = (okCallback: any) => {
  Modal.confirm({
    title: '删除',
    content: '确定删除吗？',
    okText: '确认',
    cancelText: '取消',
    onOk: () => okCallback && okCallback(),
  });
}

/**
 * 保存
 * @param form
 * @param moduleUrl
 * @param extraParams 额外参数
 * @param successCallback 成功回调
 * @param errorCallback 失败回调
 */
export const handleSave = (form: FormInstance, moduleUrl: string, extraParams?: {}, successCallback?: any, errorCallback?: any) => {
  const hide = message.loading('正在保存');
  form.validateFields().then(async () => {
    try {
      await save(moduleUrl, Object.assign({}, form.getFieldsValue(), extraParams));
      hide();
      message.success('保存成功');
      successCallback && successCallback()
      return true;
    } catch (error) {
      hide();
      message.error('保存失败！');
      errorCallback && errorCallback()
      return false;
    }
  }).catch(() => {
    hide();
    message.error('保存失败！有必填项未填！');
  })
}

/**
 * 跳转页面
 * @param url
 */
export const jumpPage = (url: string) => {
  history.push(url)
}

/**
 * form插入数据（支持复杂类型：例user.id）
 * @param form
 * @param data
 * @param needExtraKeys 需要插入到form的额外的数据的key，以“,”分割（主要应对本身form中没有，data里有的情况）
 */
export const formSetFieldsValue = (form: FormInstance, data: {}, needExtraKeys?: string) => {
  form.setFieldsValue(data)
  let formData = form.getFieldsValue();
  for (let key in formData) {
    // 如果formData的key包含“.”，说明为复杂类型，需要额外插入
    if (key.indexOf(".") !== -1) {
      let keys = key.split(".");
      // 获取object
      let valueObject = data[keys[0]]
      if (valueObject) {
        form.setFieldsValue({[key]: valueObject[keys[1]]})
      }
    }
  }
  if (needExtraKeys) {
    let needExtraKeyArray = needExtraKeys.split(",");
    needExtraKeyArray.forEach((needExtraKey) => {
      let keys = needExtraKey.split(".");
      // 获取object
      let valueObject = data[keys[0]]
      if (valueObject) {
        form.setFieldsValue({[needExtraKey]: valueObject[keys[1]]})
      }
    })
  }
}

/**
 * 转为int
 * @param string
 */
export const toInt = (string?: string) => {
  let result;
  if (string) {
    if (!isNaN(parseInt(string))) {
      result = parseInt(string)
    }
  }
  return result;
}

/**
 * 转为float
 * @param string
 */
export const toFloat = (string?: string) => {
  let result;
  if (string) {
    if (!isNaN(parseFloat(string))) {
      result = parseFloat(string)
    }
  }
  return result;
}

/**
 * 制作selectOptions数据
 * @param dataArray 数据
 * @param labelKey  label数据json中的key值
 * @param valueKey  value数据json中的key值
 */
export const makeSelectOptionsData = (dataArray: {}[], labelKey: string, valueKey: string) => {
  let result: any[] = [];
  if (dataArray && dataArray.length > 0) {
    dataArray.forEach((data) => {
      result.push({label: data[labelKey], value: data[valueKey]})
    })
  }
  return result;
}

/**
 * 两个浮点数求和
 * @param num1
 * @param num2
 */
export const add = (num1: any, num2: any) => {
  let r1, r2, m;
  try {
    r1 = num1.toString().split('.')[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = num2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  // return (num1*m+num2*m)/m;
  return Math.round(num1 * m + num2 * m) / m;
}

/**
 * 两个浮点数相减
 * @param num1
 * @param num2
 */
export const subtract = (num1: any, num2: any) => {
  let r1, r2, m;
  try {
    r1 = num1.toString().split('.')[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = num2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  let n = (r1 >= r2) ? r1 : r2;
  return (Math.round(num1 * m - num2 * m) / m).toFixed(n);
}

/**
 * 两个浮点数相除
 * @param num1
 * @param num2
 */
export const divide = (num1: any, num2: any) => {
  let t1, t2, r1, r2;
  try {
    t1 = num1.toString().split('.')[1].length;
  } catch (e) {
    t1 = 0;
  }
  try {
    t2 = num2.toString().split(".")[1].length;
  } catch (e) {
    t2 = 0;
  }
  r1 = Number(num1.toString().replace(".", ""));
  r2 = Number(num2.toString().replace(".", ""));
  return (r1 / r2) * Math.pow(10, t2 - t1);
}

/**
 * 两个浮点数相乘
 * @param num1
 * @param num2
 */
export const multiply = (num1: any, num2: any) => {
  let m = 0, s1 = num1.toString(), s2 = num2.toString();
  try {
    m += s1.split(".")[1].length
  } catch (e) {
  }
  try {
    m += s2.split(".")[1].length
  } catch (e) {
  }
  ;
  return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
}

